/*
 * Copyright 2002-2022 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.web.servlet.handler;

import java.util.ArrayList;
import java.util.List;

import org.springframework.util.StringUtils;

/**
 * <p>
 *     主要功能
 * 			基于 Bean 名称的映射：BeanNameUrlHandlerMapping 会检查传入请求的 URL，并尝试在 Spring 应用上下文中找到一个名称与 URL 匹配的 Bean 来作为处理器。
 * 			简单配置：对于那些需要非常直接地将 URL 映射到特定处理器的情况，这种方式提供了一个简洁的解决方案。
 * 		使用场景
 * 			尽管现在更常用的是基于注解的方式来进行请求映射，但在某些情况下，BeanNameUrlHandlerMapping 仍然有用：
 * 			遗留系统迁移：如果你正在从旧版本的 Spring 迁移应用，或者你的项目依赖于一些老式的配置方式，那么你可能会遇到或继续使用这种方式。
 * 			简单的 URL 映射需求：当你的应用有非常直接的 URL 到处理器的映射需求，而不需要复杂的条件判断时，可以考虑使用这种方式
 *
 * 		配置示例
 * 			以下是如何在 Spring 配置类中启用 BeanNameUrlHandlerMapping 并定义相应的控制器 Bean 的示例
 *
 * 		import org.springframework.context.annotation.Bean;
 * 		import org.springframework.context.annotation.Configuration;
 * 		import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping;
 * 		import org.springframework.web.servlet.mvc.ParameterizableViewController;
 *
 * 		@Configuration
 * 		public class WebConfig {
 *     		@Bean
 *     		public BeanNameUrlHandlerMapping beanNameUrlHandlerMapping() {
 *         		return new BeanNameUrlHandlerMapping();
 *     		}
 *     		@Bean(name = "/hello")
 *     		public ParameterizableViewController helloController() {
 *         		ParameterizableViewController controller = new ParameterizableViewController();
 *         		controller.setViewName("helloView"); // 视图名称
 *         		return controller;
 *     		}
 * 		}
 * 		在这个例子中，我们创建了一个名为 /hello 的控制器 Bean。这意味着任何对 /hello 路径的 HTTP 请求都将由这个 Bean 处理，并返回视图名为 helloView 的响应。
 *
 * 	注意事项
 * 		命名规范：为了使 BeanNameUrlHandlerMapping 正确工作，你需要确保控制器 Bean 的名称与 URL 路径相匹配。
 * 				例如，如果有一个 URL /example，那么对应的控制器 Bean 必须命名为 example 或者以 /example 开头。
 * 		优先级设置：如果同时存在多个 HandlerMapping 实现，Spring 会按照它们的 order 属性值从小到大依次尝试匹配。默认情况下，BeanNameUrlHandlerMapping 的顺序值为 Integer.MAX_VALUE - 1，这意味着它具有较低的优先级。你可以通过设置其 order 属性来调整优先级。
 * 		局限性：与 RequestMappingHandlerMapping 相比，BeanNameUrlHandlerMapping 缺乏灵活性和强大的路由能力。它不支持基于方法级别的细粒度控制，也不支持复杂的条件匹配（如 HTTP 方法、请求参数等）。
 *  总结
 * 		尽管 BeanNameUrlHandlerMapping 提供了一种快速将 URL 映射到处理器的方法，但其适用范围相对有限，主要适用于那些需要极其简单直接的 URL 到处理器映射的应用场景。随着 Spring MVC 向注解驱动的发展，大多数开发者会选择使用更为灵活和功能丰富的 RequestMappingHandlerMapping 来进行请求映射，因为它能够更好地满足现代 Web 应用的需求。然而，在特定情况下，了解并适当利用 BeanNameUrlHandlerMapping 依然可以帮助简化应用的某些部分。
 * </p>
 * Implementation of the {@link org.springframework.web.servlet.HandlerMapping}
 * interface that maps from URLs to beans with names that start with a slash ("/"),
 * similar to how Struts maps URLs to action names.
 *
 * <p>This is the default implementation used by the
 * {@link org.springframework.web.servlet.DispatcherServlet}, along with
 * {@link org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping}.
 * Alternatively, {@link SimpleUrlHandlerMapping} allows for customizing a
 * handler mapping declaratively.
 *
 * <p>The mapping is from URL to bean name. Thus an incoming URL "/foo" would map
 * to a handler named "/foo", or to "/foo /foo2" in case of multiple mappings to
 * a single handler.
 *
 * <p>Supports direct matches (given "/test" -&gt; registered "/test") and "*"
 * matches (given "/test" -&gt; registered "/t*"). For details on the pattern
 * options, see the {@link org.springframework.web.util.pattern.PathPattern}
 * javadoc.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @see SimpleUrlHandlerMapping
 */
public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {

	/**
	 * Checks name and aliases of the given bean for URLs, starting with "/".
	 */
	@Override
	protected String[] determineUrlsForHandler(String beanName) {
		List<String> urls = new ArrayList<>();
		if (beanName.startsWith("/")) {
			urls.add(beanName);
		}
		String[] aliases = obtainApplicationContext().getAliases(beanName);
		for (String alias : aliases) {
			if (alias.startsWith("/")) {
				urls.add(alias);
			}
		}
		return StringUtils.toStringArray(urls);
	}

}
